package cn.deschen.eshop.user.service.impl;

import cn.deschen.eshop.common.enums.GlobalEnum;
import cn.deschen.eshop.common.exception.GlobalException;
import cn.deschen.eshop.generator.mapper.UmsAdminMapper;
import cn.deschen.eshop.generator.model.UmsAdmin;
import cn.deschen.eshop.generator.model.UmsAdminExample;
import cn.deschen.eshop.generator.model.UmsResource;
import cn.deschen.eshop.user.auth.AdminUserDetails;
import cn.deschen.eshop.user.dao.UmsAdminRoleDao;
import cn.deschen.eshop.user.dto.req.UmsAdminRegisterReqDto;
import cn.deschen.eshop.user.service.UmsAdminCacheService;
import cn.deschen.eshop.user.service.UmsAdminService;
import cn.hutool.core.collection.CollectionUtil;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @Author hanbin_chen
 * @Description 后台用户管理Service
 * @DateTime 2021/2/4 10:52
 * @Version V1.0.0
 */
@Service
@Slf4j
@Accessors
public class UmsAdminServiceImpl implements UmsAdminService {

    @Autowired
    private UmsAdminMapper umsAdminMapper;

    @Autowired
    private UmsAdminCacheService umsAdminCacheService;

    @Autowired
    private UmsAdminRoleDao adminRoleDao;

    @Autowired
    private MapperFacade mapperFacade;

    @Override
    public UserDetails loadUserByUsername(String username) {
        UmsAdmin admin = getAdminByUsername(username);
        List<UmsResource> resourceList = getResourceListByAdminId(admin.getId());
        return new AdminUserDetails(admin, resourceList);
    }

    @Override
    @Transactional
    public UmsAdmin register(UmsAdminRegisterReqDto adminRegisterReqDto) {
        // 判断用户是否已存在
        UmsAdminExample adminExample = new UmsAdminExample();
        adminExample.createCriteria()
                .andUsernameEqualTo(adminRegisterReqDto.getUsername());
        List<UmsAdmin> admins = umsAdminMapper.selectByExample(adminExample);
        if (CollectionUtil.isNotEmpty(admins)) {
            throw new GlobalException(GlobalEnum.OPERATION_ERROR, "该用户已存在");
        }
        // 否则注册新用户
        UmsAdmin admin = mapperFacade.map(adminRegisterReqDto, UmsAdmin.class);
        int count = umsAdminMapper.insertSelective(admin);
        if (count == 0) {
            throw new GlobalException(GlobalEnum.OPERATION_ERROR, "用户注册失败");
        }

        return admin;
    }

    /**
     * 根据用户id获取用户对应的权限资源
     * @param adminId
     * @return
     */
    private List<UmsResource> getResourceListByAdminId(Long adminId) {
        List<UmsResource> resourceList = umsAdminCacheService.getResourceListById(adminId);
        // 判单资源是否为空,不为空直接返回
        if (CollectionUtil.isNotEmpty(resourceList)) {
            return resourceList;
        }
        // 缓存资源为空，从数据库获取
        resourceList = adminRoleDao.getResourceListByAdminId(adminId);
        umsAdminCacheService.setResourceListById(adminId, resourceList);
        return resourceList;
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param username
     * @return
     */
    private UmsAdmin getAdminByUsername(String username) {
        UmsAdmin admin = umsAdminCacheService.getAdminByUsername(username);
        // 缓存中用户信息存在则直接返回
        if (null != admin) {
            return admin;
        }
        // 缓存无用户信息就从数据库获取
        UmsAdminExample umsAdminExample = new UmsAdminExample();
        umsAdminExample.createCriteria().andUsernameEqualTo(username);
        List<UmsAdmin> umsAdminList = umsAdminMapper.selectByExample(umsAdminExample);
        // 判断数据库的用户是否存在或是否多个，多个就报异常
        if (CollectionUtil.isNotEmpty(umsAdminList) && umsAdminList.size() > 1) {
            log.error("【用户模块】根据用户名获取用户信息失败");
            throw new UsernameNotFoundException("用户名或密码错误");
        }
        // 获取数据库中的用户信息
        admin = umsAdminList.get(0);
        umsAdminCacheService.setAdminByUsername(username, admin);
        return admin;

    }
}
